import {
  Controller,
  Post,
  Body,
  UseGuards,
  Get,
  Param,
  Put,
  Delete,
  BadRequestException,
  ForbiddenException,
} from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { JwtAuthGuard } from '@/modules/user/jwt/jwt-auth.guard';
import { OptionalAuthGuard } from '@/modules/user/jwt/optional-auth.guard';
import { UserEntity } from '@/types/modules/user/entities/user.entity';
import { AccessControlService } from './access-control.service';
import {
  Action,
  DocPermission,
  PermissionPolicy,
  ProjectRole,
} from '../types/auth.type';
import { CurrentUser } from '@/decorators/current.user';

/**
 * 权限检查请求
 */
export class CheckPermissionReqDto {
  projectId: string;
  path: string;
  action: Action;
}

/**
 * 批量权限检查请求
 */
export class CheckBatchPermissionsReqDto {
  projectId: string;
  path: string;
  actions: Action[];
}

/**
 * 获取用户权限请求
 */
export class GetUserPermissionsReqDto {
  projectId: string;
  path: string;
}

/**
 * 🆕 配置公开访问请求
 */
export class ConfigurePublicAccessReqDto {
  /** 是否启用公开访问 */
  enabled: boolean;

  /** 系统生成的唯一标识符（可选，不传则自动生成） */
  publicIdentifier?: string;

  /** 游客权限策略（可选） */
  policies?: PermissionPolicy[];

  /** 自定义域名配置（可选） */
  customDomain?: {
    domain: string;
    forceHttps?: boolean; // 默认 true
  };
}

/**
 * 权限检查响应
 */
export class CheckPermissionResDto {
  allowed: boolean;
  reason?: string;
  matchedPolicy?: any;
}

/**
 * 批量权限检查响应
 */
export class CheckBatchPermissionsResDto {
  permissions: Record<Action, boolean>;
}

/**
 * 获取用户权限响应
 */
export class GetUserPermissionsResDto {
  actions: Action[];
}

/**
 * 添加项目成员请求
 */
export class AddMemberReqDto {
  projectId: string;
  userId: number;
  role?: ProjectRole;
  documentPermission?: DocPermission;
}

/**
 * 更新项目成员请求
 */
export class UpdateMemberReqDto {
  role?: ProjectRole;
  documentPermission?: DocPermission;
}

@ApiTags('访问控制')
@Controller('access-control')
export class AccessControlController {
  constructor(private readonly accessControlService: AccessControlService) {}

  @ApiOperation({ summary: '检查单个权限' })
  @UseGuards(JwtAuthGuard)
  @Post('check')
  async checkPermission(
    @CurrentUser() user: UserEntity,
    @Body() body: CheckPermissionReqDto,
  ): Promise<CheckPermissionResDto> {
    const result = await this.accessControlService.checkPermission(
      user.id,
      {
        projectId: body.projectId,
        path: body.path,
      },
      body.action,
    );

    return {
      allowed: result.allowed,
      reason: result.reason,
      matchedPolicy: result.matchedPolicy,
    };
  }

  @ApiOperation({ summary: '批量检查权限' })
  @UseGuards(JwtAuthGuard)
  @Post('check-batch')
  async checkBatchPermissions(
    @CurrentUser() user: UserEntity,
    @Body() body: CheckBatchPermissionsReqDto,
  ): Promise<CheckBatchPermissionsResDto> {
    const permissions = await this.accessControlService.checkPermissions(
      user.id,
      {
        projectId: body.projectId,
        path: body.path,
      },
      body.actions,
    );

    return { permissions };
  }

  @ApiOperation({ summary: '获取用户在指定文件的所有权限' })
  @UseGuards(JwtAuthGuard)
  @Post('permissions')
  async getUserPermissions(
    @CurrentUser() user: UserEntity,
    @Body() body: GetUserPermissionsReqDto,
  ): Promise<GetUserPermissionsResDto> {
    const actions = await this.accessControlService.getUserPermissions(
      user.id,
      body.projectId,
      body.path,
    );

    return { actions };
  }

  @ApiOperation({ summary: '获取项目成员的角色和权限信息' })
  @UseGuards(JwtAuthGuard)
  @Get('project/:projectId/member/:userId')
  async getProjectMemberInfo(
    @CurrentUser() user: UserEntity,
    @Param('projectId') projectId: string,
    @Param('userId') targetUserId: string,
  ) {
    const project = await this.accessControlService.getProjectInfo(projectId);
    if (!project) {
      throw new BadRequestException('项目不存在');
    }

    // 检查请求者是否有权限查看成员信息
    const hasPermission = await this.accessControlService.checkPermission(
      user.id,
      { projectId, path: '/' },
      'grant',
    );

    if (!hasPermission.allowed && project.userId !== user.id) {
      throw new ForbiddenException('您没有查看项目成员信息的权限');
    }

    const member = project.member?.find(
      (m) => m.userId === parseInt(targetUserId),
    );
    if (!member) {
      throw new BadRequestException('用户不是项目成员');
    }

    return {
      projectId,
      userId: targetUserId,
      role: member.role || 'guest',
      documentPermission: member.documentPermission,
      policies: member.policies || [],
      canEdit: member.documentPermission === 'edit',
      joinedAt: member.inviteAt,
      invitedBy: member.inviteBy,
    };
  }

  @ApiOperation({ summary: '添加项目成员' })
  @UseGuards(JwtAuthGuard)
  @Post('member')
  async addProjectMember(
    @CurrentUser() user: UserEntity,
    @Body() body: AddMemberReqDto,
  ) {
    // 检查请求者是否有权限添加成员
    const hasPermission = await this.accessControlService.checkPermission(
      user.id,
      { projectId: body.projectId, path: '/' },
      'grant',
    );

    if (!hasPermission.allowed) {
      throw new ForbiddenException('您没有添加项目成员的权限');
    }

    const success = await this.accessControlService.addProjectMember(
      body.projectId,
      body.userId,
      {
        role: body.role,
        documentPermission: body.documentPermission,
        inviteBy: user.id,
      },
    );

    return {
      success,
      message: success ? '成员添加成功' : '成员添加失败',
    };
  }

  @ApiOperation({ summary: '更新项目成员权限' })
  @UseGuards(JwtAuthGuard)
  @Put('member/:projectId/:userId')
  async updateProjectMember(
    @CurrentUser() user: UserEntity,
    @Param('projectId') projectId: string,
    @Param('userId') targetUserId: string,
    @Body() body: UpdateMemberReqDto,
  ) {
    // 检查请求者是否有权限管理成员
    const hasPermission = await this.accessControlService.checkPermission(
      user.id,
      { projectId, path: '/' },
      'grant',
    );

    if (!hasPermission.allowed) {
      throw new ForbiddenException('您没有管理项目成员的权限');
    }

    const success = await this.accessControlService.updateProjectMember(
      projectId,
      parseInt(targetUserId),
      body,
      user.id,
    );

    return {
      success,
      message: success ? '成员权限更新成功' : '成员权限更新失败',
    };
  }

  @ApiOperation({ summary: '移除项目成员' })
  @UseGuards(JwtAuthGuard)
  @Delete('member/:projectId/:userId')
  async removeProjectMember(
    @CurrentUser() user: UserEntity,
    @Param('projectId') projectId: string,
    @Param('userId') targetUserId: string,
  ) {
    // 检查请求者是否有权限移除成员
    const hasPermission = await this.accessControlService.checkPermission(
      user.id,
      { projectId, path: '/' },
      'grant',
    );

    if (!hasPermission.allowed) {
      throw new ForbiddenException('您没有移除项目成员的权限');
    }

    const success = await this.accessControlService.removeProjectMember(
      projectId,
      parseInt(targetUserId),
    );

    return {
      success,
      message: success ? '成员移除成功' : '成员移除失败',
    };
  }

  @ApiOperation({ summary: '获取项目成员列表' })
  @UseGuards(JwtAuthGuard)
  @Get('member/project/:projectId')
  async getProjectMembers(
    @CurrentUser() user: UserEntity,
    @Param('projectId') projectId: string,
  ) {
    // 检查请求者是否有权限查看成员列表
    const hasPermission = await this.accessControlService.checkPermission(
      user.id,
      { projectId, path: '/' },
      'view',
    );

    if (!hasPermission.allowed) {
      throw new ForbiddenException('您没有查看项目成员的权限');
    }

    const members = await this.accessControlService.getProjectMembers(
      projectId,
    );

    return {
      projectId,
      members: members.map((member) => ({
        userId: member.userId,
        role: member.role || 'guest',
        documentPermission: member.documentPermission || 'view',
        policies: member.policies || [],
        canEdit: member.documentPermission === 'edit',
        joinedAt: member.inviteAt,
        invitedBy: member.inviteBy,
      })),
    };
  }

  /**
   * 🆕 配置项目的公开访问
   * 支持启用/禁用、设置域名标识、配置自定义域名、设置游客权限
   */
  @ApiOperation({ summary: '配置项目公开访问' })
  @UseGuards(JwtAuthGuard)
  @Post('public-access/:projectId/configure')
  async configurePublicAccess(
    @CurrentUser() user: UserEntity,
    @Param('projectId') projectId: string,
    @Body() body: ConfigurePublicAccessReqDto,
  ) {
    // 检查请求者是否有权限管理项目
    const hasPermission = await this.accessControlService.checkPermission(
      user.id,
      { projectId, path: '/' },
      'grant',
    );

    if (!hasPermission.allowed) {
      throw new ForbiddenException('您没有管理此项目的权限');
    }

    const result = await this.accessControlService.configurePublicAccess(
      projectId,
      body,
      user.id,
    );

    return {
      success: true,
      message: body.enabled ? '公开访问已启用' : '公开访问已禁用',
      data: result,
    };
  }

  /**
   * 🆕 获取项目的公开访问配置
   */
  @ApiOperation({ summary: '获取项目公开访问配置' })
  @UseGuards(OptionalAuthGuard) // 允许匿名用户查看基本配置
  @Get('public-access/:projectId/config')
  async getPublicAccessConfig(@Param('projectId') projectId: string) {
    const config = await this.accessControlService.getPublicAccessConfig(
      projectId,
    );

    return {
      projectId,
      ...config,
    };
  }

  /**
   * 🆕 根据标识符查找项目（用于域名访问）
   */
  @ApiOperation({ summary: '根据标识符查找项目' })
  @UseGuards(OptionalAuthGuard) // 允许匿名访问
  @Get('public-access/identifier/:identifier/project')
  async getProjectByIdentifier(@Param('identifier') identifier: string) {
    const project = await this.accessControlService.getProjectByIdentifier(
      identifier,
    );

    if (!project) {
      throw new BadRequestException('项目不存在或未开启公开访问');
    }

    return {
      projectId: project._id,
      title: project.title,
      description: project.description,
      icon: project.icon,
      publicIdentifier: project.publicIdentifier,
      customDomain: project.customDomain,
    };
  }
}
